﻿
Imports System.IO
Imports std
Imports storoomc

Public Module _amutest2

    Private Class info
        Public reader As TextReader = Nothing
        Public writer As TextWriter = Nothing
        Public data As map(Of String, String) = Nothing

        Public Sub New(ByVal reader As TextReader, ByVal writer As TextWriter)
            Me.writer = writer
            Me.reader = reader
            data = New map(Of String, String)()
        End Sub
    End Class

    Private assertFailureCount As Int64 = 0
    Private lastErrorMsg As String = Nothing

    Private Sub assert(ByVal rtn As Boolean, Optional ByVal msg As String = Nothing)
        If Not isemptystring(msg) Then
            msg = "storclient._amutest2 assert failed, " + msg
        ElseIf Not isemptystring(lastErrorMsg) Then
            msg = "storclient._amutest2 assert failed, " + lastErrorMsg
        Else
            msg = "storclient._amutest2 assert failed."
        End If
        If Not rtn Then
            raiseError(errorHandle.errorType.critical, msg)
            assertFailureCount += 1
        End If
    End Sub

    Private Function returnValueHandler(ByVal rtn As Boolean, ByVal writer As TextWriter, _
                                        ByVal action As String, Optional ByVal key As String = Nothing) As Boolean
        Dim msg As String = Nothing
        msg = action + " "
        If Not isemptystring(key) Then
            msg += "key " + key + " "
        End If

        If rtn Then
            writer.WriteLine(msg + "success.")
        Else
            writer.WriteLine(msg + "failed.")
        End If
        copy(lastErrorMsg, msg)

        Return rtn
    End Function

    Private Function randomSelectKey(ByVal info As info, ByRef key As String) As Boolean
        If info.data.size() = 0 Then
            Return False
        End If

        Dim it As map(Of String, String).iterator = Nothing
        Dim i As Int64 = 0
        i = rnd(0, info.data.size(), True)
        it = info.data.begin()
        While i > 0
            it += 1
            i -= 1
        End While

        key = (+it).first()
        Return True
    End Function

    Private Function randomNotExistingKey(ByVal info As info) As String
        Dim key As String = Nothing
        While key Is Nothing OrElse info.data.find(key) <> info.data.end()
            key = createGUID()
        End While

        Return key
    End Function

    Private Function s2b(ByVal s As String) As bytes
        Return New bytes(encoding.utf8().GetBytes(s))
    End Function

    Private Function b2s(ByVal b As bytes) As String
        If Not +b Is Nothing Then
            Return encoding.utf8().GetString(+b)
        Else
            Return Nothing
        End If
    End Function

    Private Function sbl(ByVal s As String) As Int64
        Return encoding.utf8().GetByteCount(s)
    End Function

    Private Sub read(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        Dim key As String = Nothing
        Dim f As _do(Of Boolean, Boolean) = _
            Function(ByRef rtn As Boolean) As Boolean
                Return returnValueHandler(rtn, info.writer, "read", key)
            End Function

        If rnd(0, 1) < 0.5 AndAlso randomSelectKey(info, key) Then
            Dim buff As bytes = Nothing
            assert(f(storoom.read(key, buff)))
            assert(strsame(b2s(buff), info.data(key)))
        Else
            key = randomNotExistingKey(info)
            assert(Not f(storoom.read(key, Nothing)))
        End If
    End Sub

    Private Sub write(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        Dim key As String = Nothing
        key = createGUID()

        Dim s As String = Nothing
        s = createGUID()
        assert(returnValueHandler(storoom.write(key, s2b(s)), info.writer, "write", key))
        info.data(key) += s
    End Sub

    Private Sub uniqueWrite(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        Dim key As String = Nothing
        Dim f As _do(Of Boolean, Boolean) = _
            Function(ByRef rtn As Boolean) As Boolean
                Return returnValueHandler(rtn, info.writer, "uniqueWrite", key)
            End Function
        Dim s As String = Nothing
        s = createGUID()
        If rnd(0, 1) < 0.5 AndAlso randomSelectKey(info, key) Then
            assert(Not f(storoom.uniqueWrite(key, s2b(s))))
        Else
            key = randomNotExistingKey(info)
            assert(f(storoom.uniqueWrite(key, s2b(s))))
            info.data(key) = s
        End If
    End Sub

    Private Sub delete(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        Dim key As String = Nothing
        Dim f As _do(Of Boolean, Boolean) = _
            Function(ByRef rtn As Boolean) As Boolean
                Return returnValueHandler(rtn, info.writer, "delete", key)
            End Function

        If rnd(0, 1) < 0.9 AndAlso randomSelectKey(info, key) Then
            assert(f(storoom.delete(key)))
            info.data.erase(key)
        Else
            key = randomNotExistingKey(info)
            assert(Not f(storoom.delete(key)))
        End If
    End Sub

    Private Sub seek(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        Dim key As String = Nothing
        Dim f As _do(Of Boolean, Boolean) = _
            Function(ByRef rtn As Boolean) As Boolean
                Return returnValueHandler(rtn, info.writer, "seek", key)
            End Function

        If rnd(0, 1) < 0.5 AndAlso randomSelectKey(info, key) Then
            assert(f(storoom.seek(key)))
        Else
            key = randomNotExistingKey(info)
            assert(Not f(storoom.seek(key)))
        End If
    End Sub

    Private Sub list(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        Dim l As vector(Of String) = Nothing
        assert(returnValueHandler(storoom.list(l), info.writer, "list", Convert.ToString(l.size())))
        assert(Not l Is Nothing)
        assert(info.data.size() = l.size(), Convert.ToString(info.data.size()) + "!=" + Convert.ToString(l.size()))
        For j As Int64 = 0 To l.size() - 1
            assert(info.data.find(l(j)) <> info.data.end(), l(j))
        Next
    End Sub

    Private Sub modify(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        Dim s As String = Nothing
        s = createGUID()
        Dim key As String = Nothing
        If rnd(0, 1) < 0.5 OrElse Not randomSelectKey(info, key) Then
            key = randomNotExistingKey(info)
        End If
        assert(returnValueHandler(storoom.modify(key, s2b(s)), info.writer, "modify", key))
        info.data(key) = s
    End Sub

    Private Sub sizeof(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        Dim key As String = Nothing
        Dim f As _do(Of Boolean, Boolean) = _
            Function(ByRef rtn As Boolean) As Boolean
                Return returnValueHandler(rtn, info.writer, "seek", key)
            End Function

        If rnd(0, 1) < 0.5 AndAlso randomSelectKey(info, key) Then
            Dim s As UInt64
            assert(f(storoom.sizeof(key, s)))
            assert(s = sbl(info.data(key)))
        Else
            key = randomNotExistingKey(info)
            assert(Not f(storoom.sizeof(key, Nothing)))
        End If
    End Sub

    Private Sub full(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        returnValueHandler(storoom.full(), info.writer, "full")
    End Sub

    Private Sub health(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        returnValueHandler(storoom.health(), info.writer, "health")
    End Sub

    Private Sub capacity(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        Dim cap As UInt64
        assert(returnValueHandler(storoom.capacity(cap), info.writer, "capacity", Convert.ToString(cap)))
    End Sub

    Private Sub valuesize(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        Dim valuesize As UInt64
        returnValueHandler(storoom.valuesize(valuesize), info.writer, "valuesize", Convert.ToString(valuesize))
    End Sub

    Private Sub keycount(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        Dim keycount As UInt64
        assert(returnValueHandler(storoom.keycount(keycount), info.writer, "keycount", Convert.ToString(keycount)))
        assert(keycount = info.data.size())
    End Sub

    Private Sub retire(ByVal i As Object)
        Dim info As info = Nothing
        info = convertor.cast(Of info)(i)

        assert(returnValueHandler(storoom.retire(), info.writer, "retire"))
        info.data.clear()
    End Sub

    Public Sub amutest2(ByVal args As map(Of String, vector(Of String)), ByVal host As String, ByVal port As Int32, _
                        ByVal reader As TextReader, ByVal writer As TextWriter, _
                        ByVal holdtime As Int64, ByVal livetime As Int64)
        raiseError("********** automatical storoom unittest 2 **********", errorHandle.errorType.application)
        Dim testsize As Int64 = 10000
        Dim testsizeInput As Int64
        Dim testsizeStr As String = Nothing
        If argmgr.getfirstvalue(args, "testsize", testsizeStr) AndAlso _
            convertor.toint64(testsizeStr, testsizeInput) Then
            testsize = testsizeInput
        End If
        storoom.initial(host, port, storoomc.common.talkTime.client2room.retrytimes)
        storoom.holdTime = holdtime
        storoom.liveTime = livetime

#If STRONG_WRITE Then
        randomrun.invoke(testsize, _
                         New info(reader, writer, New vector(Of String)), _
                         New randomrun.info(0.1, AddressOf read), _
                         New randomrun.info(0.5, AddressOf write), _
                         New randomrun.info(0.25, AddressOf uniqueWrite), _
                         New randomrun.info(0.05, AddressOf modify), _
                         New randomrun.info(0.005, AddressOf full), _
                         New randomrun.info(0.005, AddressOf capacity), _
                         New randomrun.info(0.04, AddressOf valuesize), _
                         New randomrun.info(0.05, AddressOf keycount))
#Else
        assert(returnValueHandler(storoom.retire(), writer, "retire"))
        randomrun.invoke(testsize, _
                         New info(reader, writer), _
                         New randomrun.info(0.1, AddressOf read), _
                         New randomrun.info(0.1, AddressOf write), _
                         New randomrun.info(0.1, AddressOf uniqueWrite), _
                         New randomrun.info(0.1, AddressOf delete), _
                         New randomrun.info(0.1, AddressOf seek), _
                         New randomrun.info(0.001, AddressOf list), _
                         New randomrun.info(0.1, AddressOf modify), _
                         New randomrun.info(0.1, AddressOf sizeof), _
                         New randomrun.info(0.029, AddressOf full), _
                         New randomrun.info(0.02, AddressOf health), _
                         New randomrun.info(0.05, AddressOf capacity), _
                         New randomrun.info(0.1, AddressOf valuesize), _
                         New randomrun.info(0.1, AddressOf keycount), _
                         New randomrun.info(0.0, AddressOf retire))
#End If
        raiseError("********** finish automatical unittest 2 ***********", errorHandle.errorType.application)
        raiseError("assert failure count ", assertFailureCount, ", rate ", _
                   Convert.ToDouble(assertFailureCount) / testsize)
    End Sub

End Module
